/**
 * 
 */
package systole.domain.signals;

import java.math.BigDecimal;
import java.util.Iterator;
import java.util.Vector;
import systole.math.MathUtils;

/**
 * @author juan
 * 
 */
public class Signal {

    /**
     * List of segments that make up the signal
     */
    private Vector<Segment> segments = null;

    /**
     * Empty Constructor
     */
    public Signal() {
        this.setSegments(new Vector<Segment>());
    }

    /**
     * @param segments  List of segments.
     */
    public Signal(Vector<Segment> segments) {
        this.setSegments(segments);
    }

    /**
     * @param segments the segments to set
     */
    public void setSegments(Vector<Segment> segments) {
        this.segments = segments;
    }

    /**
     * @return the segments
     */
    public Vector<Segment> getSegments() {
        return this.segments;
    }

    /**
     *
     * @return the signal with each segment normalized between 0 and 100.
     */
    public Signal normalizeSegmentsOfSignal() {
        Signal signal = new Signal();
        Segment segment;
        for (int i = 0; i < this.getSegments().size(); i++) {
            segment = (this.getSegments().elementAt(i).normalize());
            signal.getSegments().add(segment);
        }
        return signal;
    }

    /**
     *
     * @return The signal normalized
     */
    public Signal normalize() {
        BigDecimal min = this.getMin();
        BigDecimal max = this.getMax();
        Signal signal = new Signal();
        Segment segment;
        if (max != min) {
            BigDecimal gain = new BigDecimal(100).divide(max.subtract(min), MathUtils.CONTEXT);
            for (int i = 0; i < this.getSegments().size(); i++) {
                segment = this.getSegments().elementAt(i);
                segment.subtractValueToVector(min);
                segment.multiplyVectorBy(gain);
                signal.getSegments().add(segment);
            }
        }
        return signal;
    }

    /**
     *
     * @return the minimum value of signal.
     */
    private BigDecimal getMin() {
        BigDecimal min = new BigDecimal(1000.0);
        BigDecimal minSegment;
        for (int i = 0; i < this.getSegments().size(); i++) {
            minSegment = this.getSegments().elementAt(i).min();
            if (minSegment.compareTo(min) == -1) {
                min = minSegment;
            }
        }
        return min;
    }

    /**
     *
     * @return The maximum value of signal.
     */
    private BigDecimal getMax() {
        BigDecimal max = new BigDecimal(0.0);
        BigDecimal maxSegment;
        for (int i = 0; i < this.getSegments().size(); i++) {
            maxSegment = this.getSegments().elementAt(i).max();
            if (maxSegment.compareTo(max) == 1) {
                max = maxSegment;
            }
        }
        return max;
    }

    /**
     * @return segments size avg
     */
    public int avgSamplesNumber() {

        double avg = 0;
        Iterator<Segment> it = this.segments.iterator();

        while (it.hasNext()) {
            avg += it.next().size();
        }

        avg = Math.ceil(avg / this.segments.size());

        return (int) avg;
    }

    /**
     * @return the heart rate
     */
    public float getHeartRate() {
        if (!(this.segments.size() > 0)) {
            return 0;
        }
        int avg = 0;
        Iterator<Segment> it = this.segments.iterator();

        while (it.hasNext()) {
            avg += it.next().size();
        }

        return avg / this.segments.size();
    }

    /**
     * @return max length of segments
     */
    public int maxSamplesNumber() {
        float max = 0.0f;

        Iterator<Segment> it = this.segments.iterator();

        if (it.hasNext()) {
            max = it.next().size();
        } else {
            return 0;
        }

        while (it.hasNext()) {
            if (it.next().size() > max) {
                max = it.next().size();
            }
        }

        return (int) max;
    }

    /**
     * @return min segment size
     */
    public int minSamplesNumber() {
        float min = 0.0f;

        Iterator<Segment> it = this.segments.iterator();

        //Si tiene por lo menos un elemento
        if (it.hasNext()) {
            min = it.next().size();
        } else {
            return 0;
        }

        while (it.hasNext()) {
            if (it.next().size() < min) {
                min = it.next().size();
            }
        }

        return (int) min;
    }

    @Override
    public String toString() {
        String result = "";

        for (int i = 0; i < this.getSegments().size(); i++) {
            result = result + this.segments.elementAt(i).toString() + System.getProperty("line.separator");
        }
        return result;

    }

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((this.segments == null) ? 0 : this.segments.hashCode());
        return result;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Signal other = (Signal) obj;
        if (this.segments == null) {
            if (other.segments != null) {
                return false;
            }
        } else if (!this.segments.equals(other.segments)) {
            return false;
        }
        return true;
    }
}
